import base64
import json
import logging
import time
from random import random

import requests
from PyRsa.pyb64 import Base64
from PyRsa.pyrsa import RsaKey
from apscheduler.schedulers.background import BackgroundScheduler
from lxml import etree

logging.basicConfig(level=logging.INFO, format='%(asctime)s  %(message)s', datefmt='%a, %d %b %Y %H:%M:%S +0000',
                    filename='daka.log')
settings = {'noticeWhether': 0,
            'wechatNoticeUrl': 'https://sc.ftqq.com/SCU81346Tad0a77f758d79f6682d24da4f80151f25e4017b0115fc.send',
            'discernUrl': 'https://api.apitruecaptcha.org/one/gettext', 'uname': 'funny_keke', 'pwd': '', 'ifyzm': 0}
getPublicKeyUrl = 'http://fresh.ahau.edu.cn/yxxt-v5/xtgl/login/getPublicKey.zf'  # 获取公钥
getKaptchaUrl = 'http://fresh.ahau.edu.cn/yxxt-v5/kaptcha'  # 获取验证码
loginUrl = 'http://fresh.ahau.edu.cn/yxxt-v5/web/xsLogin/checkLogin.zf'  # 登录
dakaUrl = 'http://fresh.ahau.edu.cn/yxxt-v5/web/jkxxtb/tbBcJkxx.zf'  # 打卡
detailUrl = 'http://fresh.ahau.edu.cn/yxxt-v5/web/jkxxtb/tbJkxx.zf'  # 个人信息
students = [
    {'xh': 18112763, 'mm': 255554, 'dqszdmc': '安徽省/芜湖市/无为县', 'dqszsfdm': 340000, 'dqszsdm': 340200, 'dqszxdm': 341422},
    {'xh': 18114146, 'mm': 130022, 'dqszdmc': '安徽省/池州市/青阳县', 'dqszsfdm': 340000, 'dqszsdm': 341700, 'dqszxdm': 341723},
    {'xh': 18111546, 'mm': 'w123456', 'dqszdmc': '安徽省/合肥市/蜀山区', 'dqszsfdm': 340000, 'dqszsdm': 340100,
     'dqszxdm': 340104},
    {'xh': 18112773, 'mm': 'su216946309', 'dqszdmc': '安徽省/淮南市/田家庵区', 'dqszsfdm': 340000, 'dqszsdm': 340400,
     'dqszxdm': 340403},
    {'xh': 18111136, 'mm': 121520, 'dqszdmc': '安徽省/宿州市/泗县', 'dqszsfdm': 340000, 'dqszsdm': 341300, 'dqszxdm': 341324},
    {'xh': 18112770, 'mm': 245210, 'dqszdmc': '安徽省/合肥市/瑶海区', 'dqszsfdm': 340000, 'dqszsdm': 340100, 'dqszxdm': 340102},
    {'xh': 18112579, 'mm': 161647, 'dqszdmc': '安徽省/淮北市/烈山区', 'dqszsfdm': 340000, 'dqszsdm': 340600, 'dqszxdm': 340604},
    {'xh': 18112768, 'mm': 184014, 'dqszdmc': '安徽省/芜湖市/无为县', 'dqszsfdm': 340000, 'dqszsdm': 340200, 'dqszxdm': 341422},
    {'xh': 18114882, 'mm': '07421X', 'dqszdmc': '安徽省/南京市/鼓楼区', 'dqszsfdm': 320000, 'dqszsdm': 320100,
     'dqszxdm': 320106},
    {'xh': 18114882, 'mm': '07421X', 'dqszdmc': '安徽省/南京市/鼓楼区', 'dqszsfdm': 320000, 'dqszsdm': 320100,
     'dqszxdm': 320106},
    {'xh': 18114882, 'mm': '07421X', 'dqszdmc': '安徽省/南京市/鼓楼区', 'dqszsfdm': 320000, 'dqszsdm': 320100,
     'dqszxdm': 320106}]
headers = {'Host': 'fresh.ahau.edu.cn',
           'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0',
           'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
           'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
           'Accept-Encoding': 'gzip, deflate',
           'Connection': 'keep-alive',
           'Upgrade-Insecure-Requests': '1',
           'Pragma': 'no-cache',
           'Cache-Control': 'no-cache'}
session = requests.Session()


def send(text, desp):  # 微信通知
    if settings['noticeWhether']:
        data = {'text': text, 'desp': desp}
        requests.post(settings['wechatNoticeUrl'], data=data)
    else:
        pass


def getLoginPostData(mes, data):  # 用于登录
    rsakey = RsaKey()
    rsakey.set_public(Base64().b64tohex(mes['modulus']), Base64().b64tohex(mes['exponent']))
    enPassword = Base64().hex2b64(rsakey.rsa_encrypt(data['mm']))
    enZh = Base64().hex2b64(rsakey.rsa_encrypt(data['zh']))
    enZhlx = Base64().hex2b64(rsakey.rsa_encrypt(data['zhlx']))
    dldata = {"zhlx": enZhlx, "zh": enZh, "mm": enPassword}
    if data['yzm']:
        enYzm = Base64().hex2b64(rsakey.rsa_encrypt(data['yzm']))
        dldata.update({"yzm": enYzm})
    endldata = base64.b64encode(
        json.dumps(dldata).replace(' ', '').encode(
            "utf-8")).decode('utf-8')
    return {"dldata": endldata}


def discern(uname, pwd):
    result = {}
    try:
        data = {"userid": uname, "apikey": pwd,
                "data": base64.b64encode(session.get(getKaptchaUrl).content).decode()}
        result = requests.post(settings['discernUrl'], json=data).json()
        code = result["result"]
        return code
    except:
        send('验证码异常', str(result))
        time.sleep(60)


def daka(student):
    global session
    res = 0
    session.headers.update(headers)
    while True:  # 用户登录
        try:
            if settings['ifyzm']:
                yzm = discern(uname=settings['uname'], pwd=settings['pwd'])  # 验证码
            else:
                yzm = ''
            mes = session.get(getPublicKeyUrl).json()
            data = {'zhlx': 'xsxh', 'zh': str(student['xh']), 'mm': str(student['mm']), 'yzm': yzm}  # 登录信息
            LoginPostData = getLoginPostData(mes, data)
            if session.post(loginUrl, data=LoginPostData).json()['status'] == 'SUCCESS':
                logging.info(f"{student['xh']}登录成功")
                break
        except Exception as e:
            send("健康打卡异常", f'{student["xh"]}登录出错 异常：{e}')
            time.sleep(10)
    session.headers.update({
        'Cookie': f'JSESSIONID={session.cookies.get("JSESSIONID")}; cookiesession1={session.cookies.get("cookiesession1")}',
        'Referer': f'http://fresh.ahau.edu.cn/yxxt-v5/web/xsLogin/login.zf;jsessionid={session.cookies.get("JSESSIONID")}'})
    html = etree.HTML(session.get(detailUrl).text)
    session.headers.update({
        'X-Requested-With': 'XMLHttpRequest',
        'Content-Length': '425', 'Origin': 'http://fresh.ahau.edu.cn',
        'Referer': 'http://fresh.ahau.edu.cn/yxxt-v5/web/jkxxtb/tbJkxx.zf', 'Accept': '*/*',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', })
    try:
        if (session.post(dakaUrl,
                         data={'xh': html.xpath('//input[@id="xh"]/@value')[0],
                               'xm': html.xpath('//input[@id="xm"]/@value')[0],
                               'sjdks': html.xpath('//input[@id="sjdks"]/@value')[0],
                               'sjdjs': html.xpath('//input[@id="sjdjs"]/@value')[0],
                               'tbsj': html.xpath('//input[@id="tbsj"]/@value')[0],
                               'tbzt': html.xpath('//input[@id="tbzt"]/@value')[0],
                               'jlid': html.xpath('//input[@id="jlid"]/@value')[0],
                               'dqrq': html.xpath('//input[@id="dqrq"]/@value')[0],
                               'sjdfgbz': html.xpath('//input[@id="sjdfgbz"]/@value')[0],
                               'sjdbz': html.xpath('//input[@id="sjdbz"]/@value')[0],
                               'tw': '36.{}'.format(int(random() * 8) + 1),
                               'dqszdmc': str(student['dqszdmc']),
                               'dqszsfdm': str(student['dqszsfdm']),
                               'dqszsdm': str(student['dqszsdm']),
                               'dqszxdm': str(student['dqszxdm']),
                               'bz': '正常',
                               'ydqszsfmc': '',
                               'ydqszsmc': '',
                               'ydqszxmc': ''}).json()['status'] == 'success'):
            logging.info(f'''{html.xpath('//input[@id="xm"]/@value')[0]}打卡成功''')
            res = html.xpath('//input[@id="xm"]/@value')[0]
        else:
            send("健康打卡", f'''{html.xpath('//input[@id="xm"]/@value')[0]}打卡失败''')
    except Exception as e:
        send("健康打卡", f'{student["xh"]}打卡异常 异常：{e}')
    session.headers.clear()
    session.cookies.clear()
    return res


def run():
    for student in students:
        daka(student)


def addUser(xh, mm, dqszdmc, dqszsfdm, dqszsdm, dqszxdm):
    global students
    res = 0
    try:
        res = daka(
            {'xh': xh, 'mm': mm, 'dqszdmc': dqszdmc, 'dqszsfdm': dqszsfdm, 'dqszsdm': dqszsdm, 'dqszxdm': dqszxdm})
        students.append(
            {'xh': xh, 'mm': mm, 'dqszdmc': dqszdmc, 'dqszsfdm': dqszsfdm, 'dqszsdm': dqszsdm, 'dqszxdm': dqszxdm})
        return f'{res}添加打卡成功！'
    except:
        return res


def scheduler_run():
    scheduler = BackgroundScheduler(misfire_grace_time=60)
    scheduler.add_job(run, 'cron', hour=23)  # 早
    scheduler.add_job(run, 'cron', hour=4)  # 中
    scheduler.add_job(run, 'cron', hour=11)  # 晚
    scheduler.start()
